package com.seguriapp.service;

import static com.google.common.collect.Lists.newArrayList;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.restlet.data.MediaType;
import org.restlet.resource.ClientResource;

import com.seguriapp.common.config.GlobalConfigLoader;
import com.seguriapp.entities.MenuLink;
import com.seguriapp.entities.User;
import com.seguriapp.util.Util;

/**
 * Login Service Implementation
 * 
 * @author Tania Gonzales (taniadgv@gmail.com)
 */
public class LoginServiceImpl implements LoginService {

  private static final Logger LOGGER = Logger.getLogger(LoginServiceImpl.class);

  public ValidateCredentialsResponse validateCredentials(final ValidateCredentialsRequest request) {
    ValidateCredentialsResponse response = new ValidateCredentialsResponse();
    try {
      final String url = GlobalConfigLoader.getInstance().getGlobalConfig().getBackEndUrl()
          .concat(GlobalConfigLoader.getInstance().getGlobalConfig().getValidateCredentials());
      final ClientResource resource = new ClientResource(url);
      final String userInfoJs = resource.post(convertDataToJsonString(request.getUsername(), request.getPassword()), MediaType.TEXT_PLAIN).getText();
      LOGGER.info("Data received : \n" + userInfoJs);
      response = getJsonDataFromString(userInfoJs);
    } catch (Exception e) {
      LOGGER.error(e.getStackTrace());
    }
    return response;
  }

  private String convertDataToJsonString(final String username, final String password) {
    if (username == null && password == null) {
      return StringUtils.EMPTY;
    }
    final Map<String, Object> map = new LinkedHashMap<String, Object>();
    map.put("username", username);
    map.put("password", Util.encodeString(password));
    final JSONObject obj = new JSONObject();
    try {
      obj.put("userData", map);
    } catch (JSONException e) {
      LOGGER.error("Error converting user data to json \n", e);
    }
    LOGGER.info("Sending Data : \n" + obj.toString());
    return obj.toString();
  }

  private ValidateCredentialsResponse getJsonDataFromString(final String userInfoJs) {
    final ValidateCredentialsResponse response = new ValidateCredentialsResponse();
    final JSONObject root = JSONObject.fromObject(userInfoJs);
    JSONArray dataArray = null;
    JSONObject jo = null;
    User user = null;
    if (root.has("userData")) {
      jo = root.getJSONObject("userData");
      user = processjSONObjectUser(jo);
    }
    if (user != null) {
      response.setAdministrator(user.isAdministrator());
      response.setValid(true);
      response.setLastDateLoggedIn(user.getLastDateLoggedIn());
      response.setEntitiesList(user.getEntitiesList());
      response.setUserId(user.getId());
      final List<MenuLink> menuLinksList = newArrayList();
      if (root.has("menuLinks")) {
        dataArray = root.getJSONArray("menuLinks");
        if (dataArray != null) {
          for (int i = 0; i < dataArray.size(); i++) {
            jo = dataArray.getJSONObject(i);
            final MenuLink menuLink = processjSONObject(jo);
            if (menuLink != null){
              menuLinksList.add(menuLink);
            }
          }
        }
      }
      response.setMenuList(menuLinksList);
    } else {
      if (root.has("errorMessage")) {
        response.setErrorMessage(root.getString("errorMessage"));
      }
    }
    return response;
  }

  private User processjSONObjectUser(final JSONObject jo) {
    User user = null;
    if (jo.has("username") && jo.has("administrator") && jo.has("lastDateLoggedIn") && jo.has("entitiesList")) {
      user = new User();
      user.setUsername(jo.getString("username"));
      user.setAdministrator(jo.getBoolean("administrator"));
      user.setLastDateLoggedIn(Util.parseStringToDate(jo.getString("lastDateLoggedIn")));
      user.setId(jo.getLong("id"));
      final JSONArray dataArray = jo.getJSONArray("entitiesList");
      if (dataArray != null) {
        final List<Long> entitiesList = new ArrayList<Long>();
        for (int i = 0; i < dataArray.size(); i++) {
          final Long entityId = dataArray.getLong(i);
          entitiesList.add(entityId);
        }
        user.setEntitiesList(entitiesList);
      }
    }
    return user;
  }

  private MenuLink processjSONObject(final JSONObject jo) {
    if (jo.has("id") && jo.has("name") && jo.has("path")) {
      final MenuLink menuLink = new MenuLink();
      menuLink.setId(jo.getLong("id"));
      menuLink.setName(jo.getString("name"));
      menuLink.setPath(jo.getString("path"));
      return menuLink;
    }
    return null;
  }

}
